#include <cassert>
#include <mutex>
#include "iqueue.h"

using std::mutex;
using std::lock_guard;

template <class T>
class LockQueue : public IQueue<T>{
	public:

	LockQueue();
	~LockQueue();
	
	void Enqueue(const T& elem);
	bool Dequeue(T *presult);

	private:

	struct Item {
		Item(): pnext_(nullptr) {}
		Item(Item *pnext, const T& data): pnext_(pnext), data_(data) {}
		Item* pnext_;
		T data_;
	};

	Item* phead_;
	Item* ptail_;

	mutex mut_;
	
};

template <class T>
LockQueue<T>::LockQueue():
	phead_(nullptr),
	ptail_(nullptr) {
}

template <class T>
LockQueue<T>::~LockQueue() {
	Item *pnew_item = phead_;
	while (pnew_item) {
		Item *tmp = pnew_item;
		pnew_item = pnew_item->pnext_;
		delete tmp;
	}
}

template <class T>
void LockQueue<T>::Enqueue(const T& elem) {
	lock_guard<mutex> lck(mut_);
	Item *pnew_item = new Item(nullptr, elem);
	if (!ptail_)
		ptail_ = phead_ = pnew_item;
	ptail_->pnext_ = pnew_item;
	ptail_ = ptail_->pnext_;
}

template <class T>
bool LockQueue<T>::Dequeue(T *presult) {
	lock_guard<mutex> lck(mut_);
	assert(presult);
	if (!phead_)
		return false;
	Item *ret = phead_;
	for (int i = 0; i < 100000; ++i)
		i++;
	phead_ = phead_->pnext_;
	*presult = ret->data_;
	delete phead_;
	return true;
}

